package cn.xydpeng.springframework.beans.factory.support;

import cn.xydpeng.springframework.beans.MutablePropertyValues;
import cn.xydpeng.springframework.beans.PropertyValues;
import cn.xydpeng.springframework.beans.factory.config.BeanDefinition;
import cn.xydpeng.springframework.lang.Nullable;

/**
 * @author xydpeng
 * @version v1.0
 * @date: 2022/10/12
 * @description:
 */
public abstract class AbstractBeanDefinition implements BeanDefinition {
    public static final String SCOPE_DEFAULT = "";
    @Nullable
    private volatile Object beanClass;
    @Nullable
    private String scope = SCOPE_DEFAULT;

    private boolean abstractFlag = false;
    @Nullable
    private Boolean lazyInit;

    private MutablePropertyValues propertyValues;

    @Nullable
    private String[] initMethodNames;

    @Nullable
    private String[] destroyMethodNames;
    @Nullable
    private String[] dependsOn;
    private boolean synthetic = false;
    public Class<?> getBeanClass() throws IllegalStateException {
        Object beanClassObject = this.beanClass;
        if (beanClassObject == null) {
            throw new IllegalStateException("No bean class specified on bean definition");
        }
        if (!(beanClassObject instanceof Class)) {
            throw new IllegalStateException(
                    "Bean class name [" + beanClassObject + "] has not been resolved into an actual Class");
        }
        return (Class<?>) beanClassObject;
    }

    /**
     * Specify the class for this bean.
     *
     * @see #setBeanClassName(String)
     */
    public void setBeanClass(@Nullable Class<?> beanClass) {
        this.beanClass = beanClass;
    }

    /**
     * Specify the bean class name of this bean definition.
     */
    @Override
    public void setBeanClassName(@Nullable String beanClassName) {
        this.beanClass = beanClassName;
    }

    /**
     * Return the current bean class name of this bean definition.
     */
    @Override
    @Nullable
    public String getBeanClassName() {
        final Object clazz = this.beanClass;
        return (clazz instanceof Class ? ((Class) clazz).getName() : (String) this.beanClass);
    }

    @Override
    @Nullable
    public String getScope() {
        return this.scope;
    }

    @Override
    public void setScope(@Nullable String scope) {
        this.scope = scope;
    }

    public PropertyValues getPropertyValues() {
        if (this.propertyValues == null) {
            this.propertyValues = new MutablePropertyValues();
        }
        return propertyValues;
    }

    public void setPropertyValues(MutablePropertyValues propertyValues) {
        this.propertyValues = propertyValues != null ? propertyValues : new MutablePropertyValues();
    }

    @Override
    public boolean isSingleton() {
        return SCOPE_SINGLETON.equals(this.scope) || SCOPE_DEFAULT.equals(this.scope);
    }
    @Override
    public boolean isPrototype() {
        return SCOPE_PROTOTYPE.equals(this.scope);
    }

    @Override
    public boolean isAbstract() {
        return this.abstractFlag;
    }

    @Override
    public boolean isLazyInit() {
        return (this.lazyInit != null && this.lazyInit.booleanValue());
    }

    public String[] getInitMethodNames() {
        return initMethodNames;
    }

    public void setInitMethodNames(String... initMethodNames) {
        this.initMethodNames = initMethodNames;
    }

    public String[] getDestroyMethodNames() {
        return destroyMethodNames;
    }

    public void setDestroyMethodNames(String... destroyMethodNames) {
        this.destroyMethodNames = destroyMethodNames;
    }

    @Override
    public void setInitMethodName(String initMethodName) {
        this.initMethodNames = (initMethodName != null ? new String[]{initMethodName} : null);
    }

    @Override
    public String getInitMethodName() {
        return this.initMethodNames != null ? this.initMethodNames[0] : null;
    }

    @Override
    public void setDestroyMethodName(String destroyMethodName) {
        this.destroyMethodNames = (destroyMethodName != null ? new String[]{destroyMethodName} : null);
    }

    @Override
    public String getDestroyMethodName() {
        return this.destroyMethodNames != null ? this.destroyMethodNames[0] : null;
    }

    /**
     * Set the names of the beans that this bean depends on being initialized.
     * The bean factory will guarantee that these beans get initialized first.
     * <p>Note that dependencies are normally expressed through bean properties or
     * constructor arguments. This property should just be necessary for other kinds
     * of dependencies like statics (*ugh*) or database preparation on startup.
     */
    @Override
    public void setDependsOn(@Nullable String... dependsOn) {
        this.dependsOn = dependsOn;
    }

    /**
     * Return the bean names that this bean depends on.
     */
    @Override
    @Nullable
    public String[] getDependsOn() {
        return this.dependsOn;
    }


    /**
     * Return whether this bean definition is 'synthetic', that is,
     * not defined by the application itself.
     */
    public boolean isSynthetic() {
        return this.synthetic;
    }

    /**
     * Return the resolved autowire code,
     * (resolving AUTOWIRE_AUTODETECT to AUTOWIRE_CONSTRUCTOR or AUTOWIRE_BY_TYPE).
     * @see #AUTOWIRE_AUTODETECT
     * @see #AUTOWIRE_CONSTRUCTOR
     * @see #AUTOWIRE_BY_TYPE
     */
    public int getResolvedAutowireMode() {
        //TODO 暂未实现
        return 0;
    }

    /**
     * Return if there are constructor argument values defined for this bean.
     */
    @Override
    public boolean hasConstructorArgumentValues() {
        //TODO 暂未实现
        return false;
    }


}
